﻿package net.wangit.framework.interceptor;

import java.util.Iterator;

import net.wangit.Invocation;
import net.wangit.LabelUtil;
import net.wangit.Unit;
import net.wangit.context.ActionContext;
import net.wangit.context.LocalContext;
import net.wangit.context.MultiPartRequestWrapper;
import net.wangit.framework.action.ActionMapping;
import net.wangit.framework.config.BeanFactory;
import net.wangit.framework.config.DomainsSettings;
import net.wangit.framework.dispatcher.DefaultInvocation;
import net.wangit.framework.validation.FileValidator;
import net.wangit.framework.validation.ValidationResult;
import net.wangit.framework.validation.ValidationUtil;
import net.wangit.support.ActionInterceptor;
import net.wangit.support.Validator;
import net.wangit.util.Checker;
import net.wangit.util.ClassUtil;
import net.wangit.view.element.ElementComponent;
import net.wangit.view.element.ElementConfigurationException;
import net.wangit.view.element.component.FileElement;
import net.wangit.view.element.util.ElementUtil;
import net.wangit.view.unit.UnitFactory;


/**
 * 表单校验
 * 
 * @author watson
 * 
 */
public class ValidationAI implements ActionInterceptor {

	public ValidationAI() {
	}

	public void intercept(ActionContext ac, Invocation invocation)
			throws Exception {
		ActionMapping mapping = ((DefaultInvocation) invocation)
				.getActionMapping();
		if (validate(ac, mapping))
			invocation.invoke();
		else
			ac.getActionResult().setSuccessful(false);
	}

	private boolean validate(ActionContext ac, ActionMapping mapping) {
		String units[] = mapping.getValidateUnits();
		if (Checker.isEmpty(units))
			return true;
		boolean isMarkInvalidElements = DomainsSettings
				.isMarkInvalidElements(mapping.getDomain());
		ValidationResult vr = new ValidationResult(ac, isMarkInvalidElements);
		javax.servlet.http.HttpServletRequest request = LocalContext
				.getLocalContext().getHttpServletRequest();
		if (request instanceof MultiPartRequestWrapper) {
			MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
			if (multiWrapper.hasErrors()) {
				String error;
				Iterator<String> iterator = multiWrapper.getErrors().iterator();
				while (iterator.hasNext()) {
					error = iterator.next();
					vr.addError(error);
				}

			}
		}
		String domain = mapping.getDomain();
		for (int i = 0; i < units.length; i++) {
			validate(ac, vr, domain, units[i]);
		}
		vr.finish();
		return vr.pass();
	}

	private void validate(ActionContext ac, ValidationResult vr, String domain,
			String unitId) {
		Unit unit = UnitFactory.getUnitWithoutClone(domain, unitId);
		if (unit.size() == 0)
			return;
		vr.setUnitId(unitId);
		for (int i = 0; i < unit.size(); i++) {
			ElementComponent ec = (ElementComponent) unit.getElement(i);
			String elementId = ec.getId();
			String values[] = ac
					.getRequestParameters((new StringBuilder(String
							.valueOf(unitId))).append(".").append(elementId)
							.toString());
			if (!Checker.isEmpty(values)) {
				int queryMode = ec.getQueryMode();
				Validator validator = getValidator(ac, ec);
				String expression = ec.getValidationExpression();
				boolean required = ec.isRequired();
				int minLength = ec.getMinLength();
				int maxLength = ec.getMaxLength();
				int scale = ec.getScale();
				boolean multi = values.length > 1;
				for (int j = 0; j < values.length; j++) {
					boolean pass = true;
					String value = values[j];
					if (ec instanceof FileElement) {
						String inputName = ElementUtil.getAlias(ec);
						if (ac.getFiles(inputName) != null) {
							FileValidator fv = new FileValidator(inputName);
							String result = fv.validate(ac, value, expression,
									j);
							if (!Checker.isEmpty(result)) {
								vr.addError(j, elementId, ValidationUtil
										.getMessage(ac, ec, value, result,
												multi, j));
								pass = false;
							}
						}
						if (value == null)
							value = ac.getRequestParameter(j,
									(new StringBuilder(String.valueOf(unitId)))
											.append(".").append(elementId)
											.append(".f").toString());
					}
					if (pass) {
						StringBuffer error = validateValue(ac, ec, value, j,
								required, minLength, maxLength, scale,
								validator, expression);
						if (error.length() > 0) {
							vr.addError(j, elementId, ValidationUtil
									.getMessage(ac, ec, value,
											error.toString(), multi, j));
							pass = false;
						}
					}
					if (queryMode == 4) {
						String valuesTo[] = ac
								.getRequestParameters((new StringBuilder(String
										.valueOf(unitId))).append(".").append(
										elementId).append(".t").toString());
						String to = valuesTo[j];
						StringBuffer error = validateValue(ac, ec, to, j,
								required, minLength, maxLength, scale,
								validator, expression);
						if (error.length() > 0) {
							vr.addError(j, (new StringBuilder(String
									.valueOf(elementId))).append(".t")
									.toString(), ValidationUtil.getMessage(ac,
									ec, to, error.toString(), multi, j));
							pass = false;
						}
						if (pass && validator != null
								&& !Checker.isEmpty(value)
								&& !Checker.isEmpty(to)) {
							String result = validator.validate(ac, value, to,
									expression);
							if (!Checker.isEmpty(result))
								vr.addError(j, (new StringBuilder(String
										.valueOf(elementId))).append(".t")
										.toString(), ValidationUtil.getMessage(
										ac, ec, to, result, multi, j));
						}
					}
				}

			}
		}

	}

	private StringBuffer validateValue(ActionContext ac, ElementComponent ec,
			String value, int index, boolean required, int minLength,
			int maxLength, int scale, Validator validator, String expression) {
		StringBuffer error = new StringBuffer();
		if (Checker.isEmpty(value) || required && value.trim().equals("")) {
			validateRequired(ac, error, required);
			if (validator != null)
				validateByValidator(ac, error, value, index, validator,
						expression);
		} else {
			ec.validate(ac, error, value);
			validateMinLength(ac, error, value, minLength);
			validateMaxLength(ac, error, value, maxLength);
			validateScale(ac, error, value, scale);
			if (validator != null)
				validateByValidator(ac, error, value, index, validator,
						expression);
		}
		return error;
	}

	private void validateRequired(ActionContext ac, StringBuffer error,
			boolean required) {
		if (required)
			error.append(LabelUtil.get(ac, "system", "validation.notnull"));
	}

	private void validateMinLength(ActionContext ac, StringBuffer error,
			String value, int minLength) {
		if (minLength > 0 && value.getBytes().length < minLength) {
			if (error.length() > 0)
				error.append(", ");
			String params[] = { Integer.toString(value.getBytes().length),
					Integer.toString(minLength) };
			error.append(LabelUtil.get(ac, "system", "validation.too_short",
					params));
		}
	}

	private void validateMaxLength(ActionContext ac, StringBuffer error,
			String value, int maxLength) {
		if (maxLength > 0 && value.getBytes().length > maxLength) {
			if (error.length() > 0)
				error.append(", ");
			String params[] = { Integer.toString(value.getBytes().length),
					Integer.toString(maxLength) };
			error.append(LabelUtil.get(ac, "system", "validation.too_long",
					params));
		}
	}

	private void validateScale(ActionContext ac, StringBuffer error,
			String value, int scale) {
		if (scale > 0) {
			int index = value.indexOf(".");
			if (index >= 0 && Checker.isDecimal(value)
					&& value.substring(index + 1).length() > scale) {
				if (error.length() > 0)
					error.append(", ");
				String params[] = {
						Integer.toString(value.substring(index + 1).length()),
						Integer.toString(scale) };
				error.append(LabelUtil.get(ac, "system",
						"validation.scale_too_long", params));
			}
		}
	}

	private void validateByValidator(ActionContext ac, StringBuffer error,
			String value, int index, Validator validator, String expression) {
		String result = validator.validate(ac, value, expression, index);
		if (!Checker.isEmpty(result)) {
			if (error.length() > 0)
				error.append(", ");
			error.append(result);
		}
	}

	private Validator getValidator(ActionContext ac, ElementComponent ec) {
		String customValidator;
		customValidator = ec.getCustomValidator();
		if (Checker.isEmpty(customValidator)) {
			String validatorId = ec.getValidator();
			if (!Checker.isEmpty(validatorId))
				return BeanFactory.getValidator(validatorId);
			else
				return null;
		} else {
			try {
				return (Validator) ClassUtil.loadClass(customValidator)
						.newInstance();
			} catch (Exception e) {
				throw new ElementConfigurationException((new StringBuilder(
						"could not load Validator: ")).append(ec.getId())
						.toString(), ec.getParent().getDomain(), ec.getParent()
						.getId(), ec.getId(), "Custom Validator", e);
			}
		}
	}
}
